Spatial Inferential Statistics
Task 1 - A non-parametric test
libraries
LondonWardsSF <- st_as_sf(LondonWards)
extradata <- read_csv("https://www.dropbox.com/s/qay9q1jwpffxcqj/LondonAdditionalDataFixed.csv?raw=1")
LondonWardsSF <- merge(LondonWardsSF, extradata, by.x = "WD11CD", by.y = "Wardcode")
newvar<-0
recode<-function(variable,high,medium,low){
newvar[variable<=high]<-"High"
newvar[variable<=medium]<-"Medium"
newvar[variable<=low]<-"Low"
return(newvar)
}
summary(LondonWardsSF$AvgGCSE201)
Min. 1st Qu. Median Mean 3rd Qu. Max.
245.0 332.3 343.7 345.8 358.3 409.1
summary(LondonWardsSF$UnauthAbse)
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.2463 0.8215 1.1364 1.1286 1.4105 2.4675
attach(LondonWardsSF)
LondonWardsSF$GCSE_recode <- recode(AvgGCSE201,409.1,358.3,332.3)
LondonWardsSF$unauth_recode <- recode(UnauthAbse,2.4675,1.4105,0.8215)
H0 = “There is no relationship between low average GCSE scores in London wards and high levels of unauthorised school absence.”
Can we reject this null hypothsis by running a chi-squared test?
##what does a cross tabulation of the data look like?
chisq<-chisq.test(LondonWardsSF$GCSE_recode,LondonWardsSF$unauth_recode)
#observed counts
chisq$observed
LondonWardsSF$unauth_recode
LondonWardsSF$GCSE_recode High Low Medium
High 5 101 51
Low 76 6 74
Medium 74 49 188
#expected counts
chisq$expected
LondonWardsSF$unauth_recode
LondonWardsSF$GCSE_recode High Low Medium
High 38.9984 39.25 78.7516
Low 38.7500 39.00 78.2500
Medium 77.2516 77.75 155.9984
#chi squared statistic
chisq$statistic
X-squared
217.8617
#p-value
chisq$p.value
[1] 5.40811e-46
It would appear that our p-value is very close to 0 - certainly much less than the 0.05 (95%) or 0.01 (99%) significance level we would normally use. This tells us that there is a much < 1% chance that there is no relationship between being absent from school and the average grades you get for people living in Wards across London.
Task 2: A Parametric Test - a linear regression model
- Examine the frequency distributions in your data
varlist <- data.frame(cbind(lapply(LondonWardsSF, class)))
varlist$id <- seq(1,nrow(varlist))
qplot(AvgGCSE201, data = LondonWardsSF, geom = "histogram")

qplot(UnauthAbse, data = LondonWardsSF, gemo = "histogram")

#OK, the variables look normally distributed. Would we expect there to be a relationship?
qplot(UnauthAbse, AvgGCSE201, data = LondonWardsSF, geom = "point") + stat_smooth(method="lm", se=FALSE, size=1)

- Fit a linear model to your data
#examine the results
summary(model1)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse, data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-111.876 -10.038 0.609 9.579 56.695
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 379.558 1.830 207.45 <2e-16 ***
UnauthAbse -29.874 1.527 -19.57 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 15.39 on 623 degrees of freedom
Multiple R-squared: 0.3807, Adjusted R-squared: 0.3797
F-statistic: 383 on 1 and 623 DF, p-value: < 2.2e-16
#examine some of the diagnostic plots to see if there is any patterning in the residuals
plot(model1)




- Interpreting the results of the model summary
The coefficient (estimate) in the summary() table shows that(on average) for a 1 unit (day) increase in unauthorised absence from school, there is a reduction in the average GCSE point score of -29.874.
The p-values for the intercept and the coefficient are highly statistically significant (<0.001) so we can rely on the relationship that is being observed.
The adjusted R-squared statistic is 0.38, which tells us that 38% of the variation in GCSE scores across Wards in London can be explained by variation in unauthorised absence from school (which is quite a lot for a single variable).
Interrogating the last graph in plot(model1)which is a scatter plot of fitted values (the model estimates achieved by plugging the values and coefficients back into the regression equation) against standardised residuals, we can see no apparent patterns in the cloud of points, which suggests the model has not violated any important assumptions.
For more detail about interpreting the model outputs here, try this resource:
http://blog.yhat.com/posts/r-lm-summary.html
In addtion, the two papers by Dunn (1989) and Jones (1984) on Moodle are old, but very good!
https://doi.org/10.1080/03098268908709055
Testing for Spatial Patterns Right, so our model looks OK - on the face of it. However, we should also test that there is not any spatial clustering of residuals.
We should plot the residuals on a map to see if there is any obvious spatial clustering.

OK, so no obvious problems visually. Can we confirm this statistically just to make sure?
If you remember back to a couple of lectures ago, we can test for spatial patterns (spatial autocorrelation) using the Moran’s I statistic. Let’s try that…
library(spdep)
package ‘spdep’ was built under R version 3.4.3Loading required package: Matrix
Attaching package: ‘Matrix’
The following object is masked from ‘package:tidyr’:
expand
Loading required package: spData
package ‘spData’ was built under R version 3.4.3To access larger datasets in this package, install the spDataLarge package with:
`install.packages('spDataLarge')`
Attaching package: ‘spData’
The following objects are masked _by_ ‘.GlobalEnv’:
x, y
#Now we need to generate a spatial weights matrix (remember from the lecture). We'll start with a simple binary matrix of queen's case neighbours
#create a neighbours list
LWard_nb <- poly2nb(LondonWards, queen=T)
#plot them
plot(LWard_nb, coordinates(coordsW), col="red")
#add a map underneath
plot(LondonWards, add=T)

#create a spatial weights object from these weights
Lward.lw <- nb2listw(LWard_nb, style="C")
#now run a moran's I test on the residuals
moran.test(LondonWards@data$model1_resids, Lward.lw)
Moran I test under randomisation
data: LondonWards@data$model1_resids
weights: Lward.lw
Moran I statistic standard deviate = 12.969, p-value < 2.2e-16
alternative hypothesis: greater
sample estimates:
Moran I statistic Expectation Variance
0.3036561498 -0.0016025641 0.0005540091
OK, so here we have a statistically significant but relatively weak indication that there is some spatial clustering of residual values. A value of 0.30 (1 being perfect spatial autocorrelation, 0 being none at all) shows that there is some evidence that high residual values cluster near high values and low residual values cluster near lower values.
So what does this mean? If you recall, the residual values are the points in the scatter plot that do not fall along the blue regression line…
qplot(UnauthAbse, AvgGCSE201, data = LondonWardsSF, geom = "point") + stat_smooth(method="lm", se=FALSE, size=1)

These are the wards in London where either high unauthorised absence rates do no necessarily lead to lower GCSE scores, or low unauthorised rates do not necessarily lead to higher GCSE scores. If these places cluster in space, then there might be some unobserved underlying factor causing this. This is important is it means that the assumption of independence that regression models rely upon might be violated.
Now in our case here, there is not a clear violation of spatial independence, but it is certainly hinted at.
- Investigating further - Dummy Variables What if instead of fitting one line to our cloud of points, we could fit several depending on whether the Wards we were analysing fell into some or other group. What if the relationship between attending school and achieving good exam results varied between inner and outer London, for example. Could we test for that? Well yes we can - quite easily in fact.
If we colour the points representing Wards for Inner and Outer London differently, we can start to see that there might be something interesting going on. There seems to be a stronger relationship between absence and GCSE scores in Outer London than Inner London. We can test for this in a standard linear regression model.
p <- ggplot(LondonWardsSF, aes(x=UnauthAbse, y=AvgGCSE201))
p + geom_point(aes(colour = InnerOuter))

Dummy variables are always categorical data (inner or outer London, or red / blue etc.). When we incorporate them into a regression model, they serve the purpose of splitting our analysis into groups. In the graph above, it would mean, effectively, having a separate regression line for the red points and a separate line for the blue points.
#first, let's make sure R is reading our InnerOuter variable as a factor
LondonWardsSF$InnerOuter <- as.factor(LondonWardsSF$InnerOuter)
#now run the model
model1_dummy <- lm(AvgGCSE201 ~ UnauthAbse + InnerOuter, data = LondonWardsSF)
summary(model1_dummy)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse + InnerOuter, data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-108.256 -10.043 -0.084 9.117 58.966
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 374.630 2.239 167.328 < 2e-16 ***
UnauthAbse -28.156 1.579 -17.830 < 2e-16 ***
InnerOuterOuter 4.888 1.306 3.742 0.000199 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 15.23 on 622 degrees of freedom
Multiple R-squared: 0.3943, Adjusted R-squared: 0.3924
F-statistic: 202.5 on 2 and 622 DF, p-value: < 2.2e-16
So how can we interpret this?
Well, the dummy variable is statistically significant and the coefficient tells us the difference between the two groups (Inner and Outer London) we are comparing. In this case, it is telling us that living in a Ward in outer London will improve your average GCSE score by 4.89 points, on average, compared to if you lived in Inner London. The R-squared has increased slightly, but not by much.
You will notice that despite there being two values in our dummy variable (Inner and Outer), we only get one coefficient. This is because with dummy variables, one value is always considered to be the control (comparison/reference) group. In this case we are comparing Outer London to Inner London. If our dummy variable had more than 2 levels we would have more coefficients, but always one as the reference.
The order in which the dummy comparisons are made is determined by what is known as a ‘contrast matrix’. This determines the treatment group (1) and the control (reference) group (0). We can view the contrast matrix using the contrasts() function:
contrasts(LondonWardsSF$InnerOuter)
Outer
Inner 0
Outer 1
If we want to change the reference group, there are various ways of doing this. We can use the contrasts() function, or we can use the relevel() function. Let’s try it:
LondonWardsSF$InnerOuter <- relevel(LondonWardsSF$InnerOuter, ref="Outer")
model1_dummy <- lm(AvgGCSE201 ~ UnauthAbse + InnerOuter, data = LondonWardsSF)
summary(model1_dummy)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse + InnerOuter, data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-108.256 -10.043 -0.084 9.117 58.966
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 379.519 1.811 209.581 < 2e-16 ***
UnauthAbse -28.156 1.579 -17.830 < 2e-16 ***
InnerOuterInner -4.888 1.306 -3.742 0.000199 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 15.23 on 622 degrees of freedom
Multiple R-squared: 0.3943, Adjusted R-squared: 0.3924
F-statistic: 202.5 on 2 and 622 DF, p-value: < 2.2e-16
You will notice that the only thing that has changed (-4.888) in the model is that the coefficient for the InnerOuter variable now relates to Inner London and is now negative (meaning that living in Inner London is likely to reduce your average GCSE score by 4.89 points compared to Outer London). The rest of the model is exactly the same.
- Investigating Further - Adding More Explanatory Variables
Up until this point, the model we have fitted using lm()has been exactly the same as the scatter plot we drew at the beginning. The relationships shown in the statistical outputs of the model we can observe in scatter plot. One of the great things about regression models is they allow us to go beyond the simple 2-dimensional scatter plot and extend our anaysis into multiple dimensions. Bam!
So let’s have a go…
Hmmm, what other things might affect someone’s performance at school? If we look through our suite of other variables (here - https://rpubs.com/adam_dennett/228756) we can see that there are various candidates. Socio-economic deprivation might be a good candidate - employment is a proxy for this (employed people tend to be more well-off than unemployed people), so let’s try adding employment in. In our dataset we have a variable labelled ‘Employment’ which is the employment rate (as a %) for 16-64 year olds.
First we need to check that our variable is normally distributed:
p <- ggplot(LondonWardsSF, aes(x=Employment))
p + geom_histogram()

Yep looks OK. The employment rate for 16-64 year olds looks relatively normally distributed.
Now we should check that it’s not highly correlated with our other independent variables… (highly correlated independent variables will bias any results we get)
library(corrplot)
corrplot 0.84 loaded

##ok quite big, let's go a bit smaller and selec just a few variables...
cormat <- cor(LondonWardsDF[,c(28,60,61,71)], use="complete.obs", method="pearson")
corrplot(cormat)

Right, so it doesn’t appear that unauthorised absence from school is too highly correlated with employment rate (moderate negative correlation - what is high correlation I hear you ask? Good question - we’ll go for 0.5 and above for now, but good question), so let’s put it into the model and see what it does to the analysis…
Run the model again with a new variable added in.
model2_dummy <- lm(AvgGCSE201 ~ UnauthAbse + Employment + InnerOuter, data = LondonWardsSF)
summary(model2_dummy)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse + Employment + InnerOuter,
data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-104.874 -9.457 -0.309 9.013 58.627
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 323.8259 8.3038 38.997 < 2e-16 ***
UnauthAbse -23.0673 1.6947 -13.612 < 2e-16 ***
Employment 0.7678 0.1119 6.860 1.66e-11 ***
InnerOuterInner -5.6892 1.2658 -4.495 8.31e-06 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 14.7 on 621 degrees of freedom
Multiple R-squared: 0.437, Adjusted R-squared: 0.4343
F-statistic: 160.7 on 3 and 621 DF, p-value: < 2.2e-16
So, what do the model outputs tell us?
The first thing to note is the new variable (employment) is significant (p-value is <0.001 or ***) and positive, which means that as the employment rate in a ward goes up, so does the average GCSE Score
For a 1% increase in % of people employed in a Ward, we can expect a 0.76 point increase in the average GCSE score.
The fit of the model represented by the R-squared score has improved to aroun 43% of the variation in GSCE scores now explained by the independent variables.
Including employment in the model has increased the parameter value for the inner / outer London dummy variable.
t-values are standardised coefficient values and give a sense of the importance of each independent variable - especially when measured on different scales (the coefficients relate to the unit of measurement) - from this we can see clearly that unauthorised absence is the most important variable, but employment is more important than the inner/outer London dummy variable.
- Building the optimum model
As you might have guessed, we can keep going and add more and more variables (as long as they are not highly correlated with each other) to try and explain as much of our independent variable as possible.
Task You should try and build the optimum model of GCSE performance from your data in your LondonWards dataset. Experiment with adding different variables - when building a regression model in this way, you are trying to hit a sweet spot between increasing your R-squared value as much as possible, but with as few explanatory variables as possible.
A few things to watch out for… You should never just throw variables at a model without a good theoretical reason for why they might have an influence. Choose your variables carefully!
Be prepared to take variables out of your model either if a new variable confounds (becomes more important than) earlier variables or turns out not to be significant.
For example, let’s try adding the rate of drugs related crime (logged as it is a positively skewed variable, where as the log is normal) and the number of cars per household…
summary(model3_dummy)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse + Employment + log(DrugsRate1) +
CarsPerHH2 + InnerOuter, data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-104.022 -9.825 0.056 9.104 54.770
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 308.4173 10.3263 29.867 < 2e-16 ***
UnauthAbse -19.6005 1.8352 -10.680 < 2e-16 ***
Employment 0.7077 0.1150 6.152 1.37e-09 ***
log(DrugsRate1) 0.2804 1.0077 0.278 0.781
CarsPerHH2 14.8086 3.7292 3.971 8.00e-05 ***
InnerOuterInner 0.7253 1.9047 0.381 0.703
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 14.48 on 619 degrees of freedom
Multiple R-squared: 0.4553, Adjusted R-squared: 0.4509
F-statistic: 103.5 on 5 and 619 DF, p-value: < 2.2e-16
Interpretation OK, so now things are getting interesting. Our R-squared value has improved, but we can see that:
Our drug related crime rate variable is insignificant. Perhaps unsurprising when we think very carefully about it - drugs related crime is relatively small-scale (compared to other crimes) and therefore unlikely to affect very many school children.
Including a cars per household variable completely confounds the effects of the Inner/Outer London dummy variable. This does make sense as Inner/Outer London was always just a proxy for afluence which is captured far more effectively with the cars per household variable.
Task - continued Keep experiementing with new explanatory variables until you are happy that you have built your optium model.
When you have finished:
write your residual values out to your LondonWardsSF dataframe plot your residuals on a map to check visually for spatial autocorrelation run a Moran’s I test to confirm the presence or otherwise of spatial autocorrelation.
Task 3 - Geographically Weighted Regression Models (GWR)
Here’s my final model from the last section:
summary(model_final)
Call:
lm(formula = AvgGCSE201 ~ UnauthAbse + Employment + CarsPerHH2,
data = LondonWardsSF)
Residuals:
Min 1Q Median 3Q Max
-104.128 -9.699 0.130 9.199 55.253
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 310.5354 8.5374 36.373 < 2e-16 ***
UnauthAbse -19.7024 1.8160 -10.849 < 2e-16 ***
Employment 0.7055 0.1097 6.434 2.48e-10 ***
CarsPerHH2 13.4755 2.0906 6.446 2.31e-10 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
Residual standard error: 14.46 on 621 degrees of freedom
Multiple R-squared: 0.4551, Adjusted R-squared: 0.4525
F-statistic: 172.9 on 3 and 621 DF, p-value: < 2.2e-16




qtm(LondonWardsSF, fill = "model_final_res")

LondonWards <- as(LondonWardsSF,"Spatial")
moran.test(LondonWards@data$model1_resids, Lward.lw)
Moran I test under randomisation
data: LondonWards@data$model1_resids
weights: Lward.lw
Moran I statistic standard deviate = 12.969, p-value < 2.2e-16
alternative hypothesis: greater
sample estimates:
Moran I statistic Expectation Variance
0.3036561498 -0.0016025641 0.0005540091
Now, we probably could stop at this point, but the Moran’s I test suggests that there might be a little spatial autocorrelation in the residuals, therefore it will be worth seeing if we can learn even more about the factors affecting school performance in London using some geographically weighted models.
This part of the practical will only skirt the edges of GWR, for much more detail you should visit the GWR website which is produced and maintained by Prof Chris Brunsdon and Dr Martin Charlton who originally developed the technique - http://gwr.nuim.ie/
There are various packages which will carry out GWR in R, for this pracical we we use spgwr (mainly because it was the first one I came across), although you could also use GWmodel or gwrr. At the end of this practical, you can test out these ideas in ArcGIS using the GWR toolset in the Spatial Statistics Toolbox -
I should also acknowledge the guide on GWR (accessible here: http://www.bris.ac.uk/cmpo/events/2009/segregation/gwr.pdf) produced by the University of Bristol, which was a great help when producing this exercise.
library(spgwr)
NOTE: This package does not constitute approval of GWR
as a method of spatial analysis; see example(gwr)
#calculate kernel bandwidth
GWRbandwidth <- gwr.sel(AvgGCSE201 ~ UnauthAbse + Employment + CarsPerHH2, data = LondonWards, coords=cbind(x,y),adapt=T)
data is Spatial* object, ignoring coords argument
Adaptive q: 0.381966 CV score: 128009
Adaptive q: 0.618034 CV score: 129579.3
Adaptive q: 0.236068 CV score: 125818
Adaptive q: 0.145898 CV score: 122617.5
Adaptive q: 0.09016994 CV score: 119379.5
Adaptive q: 0.05572809 CV score: 117056.1
Adaptive q: 0.03444185 CV score: 115477
Adaptive q: 0.02128624 CV score: 114278.4
Adaptive q: 0.01315562 CV score: 113264.9
Adaptive q: 0.008130619 CV score: 113662.9
Adaptive q: 0.01319871 CV score: 113267.8
Adaptive q: 0.01201289 CV score: 113176.3
Adaptive q: 0.01053 CV score: 113129.9
Adaptive q: 0.01038398 CV score: 113113.6
Adaptive q: 0.009523271 CV score: 113079.5
Adaptive q: 0.00967515 CV score: 113066.9
Adaptive q: 0.009839582 CV score: 113069.7
Adaptive q: 0.009730461 CV score: 113067
Adaptive q: 0.009634459 CV score: 113067.3
Adaptive q: 0.00967515 CV score: 113066.9
#run the gwr model
gwr.model = gwr(AvgGCSE201 ~ UnauthAbse + Employment + CarsPerHH2, data=LondonWards, coords=cbind(x,y), adapt=GWRbandwidth, hatmatrix=TRUE, se.fit=TRUE)
data is Spatial* object, ignoring coords argument
#print the results of the model
gwr.model
Call:
gwr(formula = AvgGCSE201 ~ UnauthAbse + Employment + CarsPerHH2,
data = LondonWards, coords = cbind(x, y), adapt = GWRbandwidth,
hatmatrix = TRUE, se.fit = TRUE)
Kernel function: gwr.Gauss
Adaptive quantile: 0.00967515 (about 6 of 625 data points)
Summary of GWR coefficient estimates at data points:
Min. 1st Qu. Median 3rd Qu. Max. Global
X.Intercept. 116.023352 285.271262 320.394568 349.527999 516.089672 310.5354
UnauthAbse -54.411470 -26.629102 -18.067046 -9.256077 27.148358 -19.7024
Employment -2.012669 0.036767 0.473397 0.979962 3.261127 0.7055
CarsPerHH2 -82.068169 5.554686 17.509463 32.406615 74.444542 13.4755
Number of data points: 625
Effective number of parameters (residual: 2traceS - traceS'S): 193.2947
Effective degrees of freedom (residual: 2traceS - traceS'S): 431.7053
Sigma (residual: 2traceS - traceS'S): 12.52927
Effective number of parameters (model: traceS): 138.6919
Effective degrees of freedom (model: traceS): 486.3081
Sigma (model: traceS): 11.80494
Sigma (ML): 10.41309
AICc (GWR p. 61, eq 2.33; p. 96, eq. 4.21): 5063.047
AIC (GWR p. 96, eq. 4.22): 4841.194
Residual sum of squares: 67770.21
Quasi-global R2: 0.7155156
The output from the GWR model reveals how the coefficients vary across the 625 Wards in our London Study region. You will see how the global coefficients are exactly the same as the coefficients in the earlier lm model. In this particular model (yours will look a little different if you have used different explanatory variables), if we take unauthorised absence from school, we can see that the coefficients range from a minimum value of -54.41 (1 unit change in unauthorised absence resulting in a drop in average GCSE score of -54.41) to +27.14 (1 unit change in unauthorised absence resulting in an increase in average GCSE score of +27.14). For half of the wards in the dataset, as unauthorised absence rises by 1 point, GCSE scores will decrease between -26.62 and -9.26 points (the inter-quartile range between the 1st Qu and the 3rd Qu).
You will notice that the R-Squared value has improved - this is not uncommon for GWR models, but it doesn’t necessarily mean they are definitely better than global models. The small number of cases under the kernel means that GW models have been criticised.
Coefficient ranges can also be seen for the other variables and they suggest some interesting spatial patterning. To explore this we can plot the GWR coefficients for different variables. Firstly we can attach the coefficients to our original dataframe - this can be achieved simply as the coefficients for each ward appear in the same order in our spatial points dataframe as they do in the original dataframe.
#attach coefficients to original dataframe
LondonWards@data$coefUnauthAbse<-results$UnauthAbse
LondonWards@data$coefEmployment<-results$Employment
LondonWards@data$coefCarsPerHH2<-results$CarsPerHH2
tm_shape(LondonWards) +
tm_polygons(col = "coefUnauthAbse", palette = "RdBu")

tm_shape(LondonWards) +
tm_polygons(col = "coefEmployment", palette = "RdBu")

tm_shape(LondonWards) +
tm_polygons(col = "coefCarsPerHH2", palette = "RdBu")

Taking the first plot, which is for the unauthorised absence coefficients, we can see that for the majority of boroughs in London, there is the negative relationship we would expect - i.e. as unauthorised absence goes up, exam scores go down. For three boroughs (Westminster, Kensington & Chelsea and Hammersmith and Fulham - the richest in London), however, the relationship is positive - as unauthorised school absence increases, so does average GCSE score. This is a very interesting pattern and counterintuitive pattern, but may partly be explained the multiple homes owned by many living in these boroughs (students living in different parts of the country and indeed the world for significant periods of the year) and the over representation of private schooling of those living in these areas. If this is not the case and unauthorised absence from school is reflecting the unauthorised absence of poorer students attending local, inner city schools, then high GCSE grades may also reflect the achievements of those who are sent away to expensive fee-paying schools elsewhere in the country and who return to their parental homes later in the year. Either way, these factors could explain these results.
Of course, these results may not be statistically significant across the whole of London. Roughly speaking, if a coefficient estimate is more than 2 standard errors away from zero, then it is “statistically significant”.
To calculate standard errors, for each variable you can use a formula similar to this:
sigTest = abs(gwr.model$SDF$UnauthAbse) -2 * gwr.model$SDF$UnauthAbse_se
LondonWards$GWRUnauthSig<-sigTest
#tmaptools::palette_explorer()
If this is greater than zero (i.e. the estimate is more than two standard errors away from zero), it is very unlikely that the true value is zero, i.e. it is statistically significant (at nearly the 95% confidence level)
You should now calculate these for each variable in your GWR model and See if you can plot them on a map, for example:
tm_shape(LondonWards) +
tm_polygons(col = "GWRUnauthSig", palette = "RdYlBu")

From the results of your GWR exercise, what are you able to conclude about the geographical variation in your explanatory variables when predicting your dependent variable?
LS0tCnRpdGxlOiAiUHJhY3RpY2FsOSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyMjIyMgU3BhdGlhbCBJbmZlcmVudGlhbCBTdGF0aXN0aWNzClRhc2sgMSAtIEEgbm9uLXBhcmFtZXRyaWMgdGVzdAoKKmxpYnJhcmllcyoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbGlicmFyeShyZ2RhbCkKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoc2YpCmxpYnJhcnkoZ2dwbG90MikKYGBgCgpgYGB7cn0KTG9uZG9uV2FyZHNTRiA8LSBzdF9hc19zZihMb25kb25XYXJkcykKZXh0cmFkYXRhIDwtIHJlYWRfY3N2KCJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zL3FheTlxMWp3cGZmeGNxai9Mb25kb25BZGRpdGlvbmFsRGF0YUZpeGVkLmNzdj9yYXc9MSIpCkxvbmRvbldhcmRzU0YgPC0gbWVyZ2UoTG9uZG9uV2FyZHNTRiwgZXh0cmFkYXRhLCBieS54ID0gIldEMTFDRCIsIGJ5LnkgPSAiV2FyZGNvZGUiKQpgYGAKCmBgYHtyfQpuZXd2YXI8LTAKcmVjb2RlPC1mdW5jdGlvbih2YXJpYWJsZSxoaWdoLG1lZGl1bSxsb3cpewogIG5ld3Zhclt2YXJpYWJsZTw9aGlnaF08LSJIaWdoIgogIG5ld3Zhclt2YXJpYWJsZTw9bWVkaXVtXTwtIk1lZGl1bSIKICBuZXd2YXJbdmFyaWFibGU8PWxvd108LSJMb3ciCiAgcmV0dXJuKG5ld3ZhcikKfQpgYGAKCmBgYHtyfQpzdW1tYXJ5KExvbmRvbldhcmRzU0YkQXZnR0NTRTIwMSkKYGBgCgpgYGB7cn0Kc3VtbWFyeShMb25kb25XYXJkc1NGJFVuYXV0aEFic2UpCmBgYAoKYGBge3J9CmF0dGFjaChMb25kb25XYXJkc1NGKQpMb25kb25XYXJkc1NGJEdDU0VfcmVjb2RlIDwtIHJlY29kZShBdmdHQ1NFMjAxLDQwOS4xLDM1OC4zLDMzMi4zKQpMb25kb25XYXJkc1NGJHVuYXV0aF9yZWNvZGUgPC0gcmVjb2RlKFVuYXV0aEFic2UsMi40Njc1LDEuNDEwNSwwLjgyMTUpCmBgYAoKSDAgID0g4oCcVGhlcmUgaXMgbm8gcmVsYXRpb25zaGlwIGJldHdlZW4gbG93IGF2ZXJhZ2UgR0NTRSBzY29yZXMgaW4gTG9uZG9uIHdhcmRzIGFuZCBoaWdoIGxldmVscyBvZiB1bmF1dGhvcmlzZWQgc2Nob29sIGFic2VuY2Uu4oCdCgpDYW4gd2UgcmVqZWN0IHRoaXMgbnVsbCBoeXBvdGhzaXMgYnkgcnVubmluZyBhIGNoaS1zcXVhcmVkIHRlc3Q/CgpgYGB7cn0KIyN3aGF0IGRvZXMgYSBjcm9zcyB0YWJ1bGF0aW9uIG9mIHRoZSBkYXRhIGxvb2sgbGlrZT8KCmNoaXNxPC1jaGlzcS50ZXN0KExvbmRvbldhcmRzU0YkR0NTRV9yZWNvZGUsTG9uZG9uV2FyZHNTRiR1bmF1dGhfcmVjb2RlKQojb2JzZXJ2ZWQgY291bnRzCmNoaXNxJG9ic2VydmVkCmBgYAoKYGBge3J9CiNleHBlY3RlZCBjb3VudHMKY2hpc3EkZXhwZWN0ZWQKYGBgCgpgYGB7cn0KI2NoaSBzcXVhcmVkIHN0YXRpc3RpYwpjaGlzcSRzdGF0aXN0aWMKYGBgCgpgYGB7cn0KI3AtdmFsdWUKY2hpc3EkcC52YWx1ZQpgYGAKCkl0IHdvdWxkIGFwcGVhciB0aGF0IG91ciBwLXZhbHVlIGlzIHZlcnkgY2xvc2UgdG8gMCAtIGNlcnRhaW5seSBtdWNoIGxlc3MgdGhhbiB0aGUgMC4wNSAoOTUlKSBvciAwLjAxICg5OSUpIHNpZ25pZmljYW5jZSBsZXZlbCB3ZSB3b3VsZCBub3JtYWxseSB1c2UuIFRoaXMgdGVsbHMgdXMgdGhhdCB0aGVyZSBpcyBhIG11Y2ggPCAxJSBjaGFuY2UgdGhhdCB0aGVyZSBpcyBubyByZWxhdGlvbnNoaXAgYmV0d2VlbiBiZWluZyBhYnNlbnQgZnJvbSBzY2hvb2wgYW5kIHRoZSBhdmVyYWdlIGdyYWRlcyB5b3UgZ2V0IGZvciBwZW9wbGUgbGl2aW5nIGluIFdhcmRzIGFjcm9zcyBMb25kb24uCgpUYXNrIDI6IEEgUGFyYW1ldHJpYyBUZXN0IC0gYSBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbAoKMS4gRXhhbWluZSB0aGUgZnJlcXVlbmN5IGRpc3RyaWJ1dGlvbnMgaW4geW91ciBkYXRhCmBgYHtyfQp2YXJsaXN0IDwtIGRhdGEuZnJhbWUoY2JpbmQobGFwcGx5KExvbmRvbldhcmRzU0YsIGNsYXNzKSkpCnZhcmxpc3QkaWQgPC0gc2VxKDEsbnJvdyh2YXJsaXN0KSkKCnFwbG90KEF2Z0dDU0UyMDEsIGRhdGEgPSBMb25kb25XYXJkc1NGLCBnZW9tID0gImhpc3RvZ3JhbSIpCmBgYAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcXBsb3QoVW5hdXRoQWJzZSwgZGF0YSA9IExvbmRvbldhcmRzU0YsIGdlbW8gPSAiaGlzdG9ncmFtIikKYGBgCgpgYGB7cn0KI09LLCB0aGUgdmFyaWFibGVzIGxvb2sgbm9ybWFsbHkgZGlzdHJpYnV0ZWQuIFdvdWxkIHdlIGV4cGVjdCB0aGVyZSB0byBiZSBhIHJlbGF0aW9uc2hpcD8KCnFwbG90KFVuYXV0aEFic2UsIEF2Z0dDU0UyMDEsIGRhdGEgPSBMb25kb25XYXJkc1NGLCBnZW9tID0gInBvaW50IikgKyBzdGF0X3Ntb290aChtZXRob2Q9ImxtIiwgc2U9RkFMU0UsIHNpemU9MSkKYGBgCgoyLiBGaXQgYSBsaW5lYXIgbW9kZWwgdG8geW91ciBkYXRhCmBgYHtyfQojSXQgbG9va3MgbGlrZSB0aGVyZSBpcyBhIG5lZ2F0aXZlIHJlbGF0aW9uc2hpcCwgc28gY2FuIHdlIGRpc2NvdmVyIGV4YWN0bHkgd2hhdCB0aGlzIHJlbGF0aW9uc2hpcCBpcyB1c2luZyBhIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsICh3ZSBhY3R1YWxseSBmaXR0ZWQgb25lIGFib3ZlIHRvIGNyZWF0ZSB0aGUgYmx1ZSBsaW5lKQpsaWJyYXJ5KGJyb29tKQoKI3RvIGZpdCB0aGUgbGluZWFyIHJlZ3Jzc2lvbiBtb2RlbCwgdXNlIHRoZSBsbSgpIGZ1bmN0aW9uCm1vZGVsMSA8LSBsbShBdmdHQ1NFMjAxIH4gVW5hdXRoQWJzZSwgZGF0YSA9IExvbmRvbldhcmRzU0YpCiN3cml0ZSB0aGUgcmVzdWx0cyBvdXQgaW50byBhIGRhdGFmcmFtZQptb2RlbDFfcmVzIDwtIHRpZHkobW9kZWwxKQoKI2V4YW1pbmUgdGhlIHJlc3VsdHMKc3VtbWFyeShtb2RlbDEpCmBgYAoKYGBge3J9CiNleGFtaW5lIHNvbWUgb2YgdGhlIGRpYWdub3N0aWMgcGxvdHMgdG8gc2VlIGlmIHRoZXJlIGlzIGFueSBwYXR0ZXJuaW5nIGluIHRoZSByZXNpZHVhbHMKcGxvdChtb2RlbDEpCmBgYAoKMy4gSW50ZXJwcmV0aW5nIHRoZSByZXN1bHRzIG9mIHRoZSBtb2RlbCBzdW1tYXJ5CiogVGhlIGNvZWZmaWNpZW50IChlc3RpbWF0ZSkgaW4gdGhlIHN1bW1hcnkoKSB0YWJsZSBzaG93cyB0aGF0KG9uIGF2ZXJhZ2UpIGZvciBhIDEgdW5pdCAoZGF5KSBpbmNyZWFzZSBpbiB1bmF1dGhvcmlzZWQgYWJzZW5jZSBmcm9tIHNjaG9vbCwgdGhlcmUgaXMgYSByZWR1Y3Rpb24gaW4gdGhlIGF2ZXJhZ2UgR0NTRSBwb2ludCBzY29yZSBvZiAtMjkuODc0LgoKKiBUaGUgcC12YWx1ZXMgZm9yIHRoZSBpbnRlcmNlcHQgYW5kIHRoZSBjb2VmZmljaWVudCBhcmUgaGlnaGx5IHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgKDwwLjAwMSkgc28gd2UgY2FuIHJlbHkgb24gdGhlIHJlbGF0aW9uc2hpcCB0aGF0IGlzIGJlaW5nIG9ic2VydmVkLgoKKiBUaGUgYWRqdXN0ZWQgUi1zcXVhcmVkIHN0YXRpc3RpYyBpcyAwLjM4LCB3aGljaCB0ZWxscyB1cyB0aGF0IDM4JSBvZiB0aGUgdmFyaWF0aW9uIGluIEdDU0Ugc2NvcmVzIGFjcm9zcyBXYXJkcyBpbiBMb25kb24gY2FuIGJlIGV4cGxhaW5lZCBieSB2YXJpYXRpb24gaW4gdW5hdXRob3Jpc2VkIGFic2VuY2UgZnJvbSBzY2hvb2wgKHdoaWNoIGlzIHF1aXRlIGEgbG90IGZvciBhIHNpbmdsZSB2YXJpYWJsZSkuCgoqIEludGVycm9nYXRpbmcgdGhlIGxhc3QgZ3JhcGggaW4gcGxvdChtb2RlbDEpd2hpY2ggaXMgYSBzY2F0dGVyIHBsb3Qgb2YgZml0dGVkIHZhbHVlcyAodGhlIG1vZGVsIGVzdGltYXRlcyBhY2hpZXZlZCBieSBwbHVnZ2luZyB0aGUgdmFsdWVzIGFuZCBjb2VmZmljaWVudHMgYmFjayBpbnRvIHRoZSByZWdyZXNzaW9uIGVxdWF0aW9uKSBhZ2FpbnN0IHN0YW5kYXJkaXNlZCByZXNpZHVhbHMsIHdlIGNhbiBzZWUgbm8gYXBwYXJlbnQgcGF0dGVybnMgaW4gdGhlIGNsb3VkIG9mIHBvaW50cywgd2hpY2ggc3VnZ2VzdHMgdGhlIG1vZGVsIGhhcyBub3QgdmlvbGF0ZWQgYW55IGltcG9ydGFudCBhc3N1bXB0aW9ucy4KCkZvciBtb3JlIGRldGFpbCBhYm91dCBpbnRlcnByZXRpbmcgdGhlIG1vZGVsIG91dHB1dHMgaGVyZSwgdHJ5IHRoaXMgcmVzb3VyY2U6CgpodHRwOi8vYmxvZy55aGF0LmNvbS9wb3N0cy9yLWxtLXN1bW1hcnkuaHRtbAoKSW4gYWRkdGlvbiwgdGhlIHR3byBwYXBlcnMgYnkgRHVubiAoMTk4OSkgYW5kIEpvbmVzICgxOTg0KSBvbiBNb29kbGUgYXJlIG9sZCwgYnV0IHZlcnkgZ29vZCEKCmh0dHBzOi8vZG9pLm9yZy8xMC4xMDgwLzAzMDk4MjY4OTA4NzA5MDU1IAoKVGVzdGluZyBmb3IgU3BhdGlhbCBQYXR0ZXJucwpSaWdodCwgc28gb3VyIG1vZGVsIGxvb2tzIE9LIC0gb24gdGhlIGZhY2Ugb2YgaXQuIEhvd2V2ZXIsIHdlIHNob3VsZCBhbHNvIHRlc3QgdGhhdCB0aGVyZSBpcyBub3QgYW55IHNwYXRpYWwgY2x1c3RlcmluZyBvZiByZXNpZHVhbHMuCgpXZSBzaG91bGQgcGxvdCB0aGUgcmVzaWR1YWxzIG9uIGEgbWFwIHRvIHNlZSBpZiB0aGVyZSBpcyBhbnkgb2J2aW91cyBzcGF0aWFsIGNsdXN0ZXJpbmcuCgpgYGB7cn0KbGlicmFyeSh0bWFwKQoKI3NhdmUgdGhlIHJlc2lkdWFscyBpbnRvIHlvdXIgZGF0YWZyYW1lCkxvbmRvbldhcmRzU0YkbW9kZWwxX3Jlc2lkcyA8LSBtb2RlbDEkcmVzaWR1YWxzCiNub3cgcGxvdCB0aGUgcmVzaWR1YWxzCnRtYXBfbW9kZSgicGxvdCIpCnF0bShMb25kb25XYXJkc1NGLCBmaWxsID0gIm1vZGVsMV9yZXNpZHMiKQpgYGAKCk9LLCBzbyBubyBvYnZpb3VzIHByb2JsZW1zIHZpc3VhbGx5LiBDYW4gd2UgY29uZmlybSB0aGlzIHN0YXRpc3RpY2FsbHkganVzdCB0byBtYWtlIHN1cmU/CgpJZiB5b3UgcmVtZW1iZXIgYmFjayB0byBhIGNvdXBsZSBvZiBsZWN0dXJlcyBhZ28sIHdlIGNhbiB0ZXN0IGZvciBzcGF0aWFsIHBhdHRlcm5zIChzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbikgdXNpbmcgdGhlIE1vcmFu4oCZcyBJIHN0YXRpc3RpYy4gTGV04oCZcyB0cnkgdGhhdOKApgoKYGBge3J9CmxpYnJhcnkoc3BkZXApCmxpYnJhcnkoc3ApCmxpYnJhcnkoc2YpCiMjIyMjCkxvbmRvbldhcmRzIDwtIGFzKExvbmRvbldhcmRzU0YsIlNwYXRpYWwiKQojRmlyc3QgY2FsY3VsYXRlIHRoZSBjZW50cm9pZHMgb2YgYWxsIFdhcmRzIGluIExvbmRvbgpjb29yZHNXIDwtIGNvb3JkaW5hdGVzKExvbmRvbldhcmRzKQpwbG90KGNvb3Jkc1cpCmBgYAoKYGBge3J9CiNOb3cgd2UgbmVlZCB0byBnZW5lcmF0ZSBhIHNwYXRpYWwgd2VpZ2h0cyBtYXRyaXggKHJlbWVtYmVyIGZyb20gdGhlIGxlY3R1cmUpLiBXZSdsbCBzdGFydCB3aXRoIGEgc2ltcGxlIGJpbmFyeSBtYXRyaXggb2YgcXVlZW4ncyBjYXNlIG5laWdoYm91cnMKI2NyZWF0ZSBhIG5laWdoYm91cnMgbGlzdApMV2FyZF9uYiA8LSBwb2x5Mm5iKExvbmRvbldhcmRzLCBxdWVlbj1UKQojcGxvdCB0aGVtCnBsb3QoTFdhcmRfbmIsIGNvb3JkaW5hdGVzKGNvb3Jkc1cpLCBjb2w9InJlZCIpCiNhZGQgYSBtYXAgdW5kZXJuZWF0aApwbG90KExvbmRvbldhcmRzLCBhZGQ9VCkKYGBgCgpgYGB7cn0KI2NyZWF0ZSBhIHNwYXRpYWwgd2VpZ2h0cyBvYmplY3QgZnJvbSB0aGVzZSB3ZWlnaHRzCkx3YXJkLmx3IDwtIG5iMmxpc3R3KExXYXJkX25iLCBzdHlsZT0iQyIpCiNub3cgcnVuIGEgbW9yYW4ncyBJIHRlc3Qgb24gdGhlIHJlc2lkdWFscwptb3Jhbi50ZXN0KExvbmRvbldhcmRzQGRhdGEkbW9kZWwxX3Jlc2lkcywgTHdhcmQubHcpCmBgYAoKT0ssIHNvIGhlcmUgd2UgaGF2ZSBhIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYnV0IHJlbGF0aXZlbHkgd2VhayBpbmRpY2F0aW9uIHRoYXQgdGhlcmUgaXMgc29tZSBzcGF0aWFsIGNsdXN0ZXJpbmcgb2YgcmVzaWR1YWwgdmFsdWVzLiBBIHZhbHVlIG9mIDAuMzAgKDEgYmVpbmcgcGVyZmVjdCBzcGF0aWFsIGF1dG9jb3JyZWxhdGlvbiwgMCBiZWluZyBub25lIGF0IGFsbCkgc2hvd3MgdGhhdCB0aGVyZSBpcyBzb21lIGV2aWRlbmNlIHRoYXQgaGlnaCByZXNpZHVhbCB2YWx1ZXMgY2x1c3RlciBuZWFyIGhpZ2ggdmFsdWVzIGFuZCBsb3cgcmVzaWR1YWwgdmFsdWVzIGNsdXN0ZXIgbmVhciBsb3dlciB2YWx1ZXMuCgpTbyB3aGF0IGRvZXMgdGhpcyBtZWFuPwpJZiB5b3UgcmVjYWxsLCB0aGUgcmVzaWR1YWwgdmFsdWVzIGFyZSB0aGUgcG9pbnRzIGluIHRoZSBzY2F0dGVyIHBsb3QgdGhhdCBkbyBub3QgZmFsbCBhbG9uZyB0aGUgYmx1ZSByZWdyZXNzaW9uIGxpbmXigKYKCmBgYHtyfQpxcGxvdChVbmF1dGhBYnNlLCBBdmdHQ1NFMjAxLCBkYXRhID0gTG9uZG9uV2FyZHNTRiwgZ2VvbSA9ICJwb2ludCIpICsgc3RhdF9zbW9vdGgobWV0aG9kPSJsbSIsIHNlPUZBTFNFLCBzaXplPTEpCmBgYAoKVGhlc2UgYXJlIHRoZSB3YXJkcyBpbiBMb25kb24gd2hlcmUgZWl0aGVyIGhpZ2ggdW5hdXRob3Jpc2VkIGFic2VuY2UgcmF0ZXMgZG8gbm8gbmVjZXNzYXJpbHkgbGVhZCB0byBsb3dlciBHQ1NFIHNjb3Jlcywgb3IgbG93IHVuYXV0aG9yaXNlZCByYXRlcyBkbyBub3QgbmVjZXNzYXJpbHkgbGVhZCB0byBoaWdoZXIgR0NTRSBzY29yZXMuIElmIHRoZXNlIHBsYWNlcyBjbHVzdGVyIGluIHNwYWNlLCB0aGVuIHRoZXJlIG1pZ2h0IGJlIHNvbWUgdW5vYnNlcnZlZCB1bmRlcmx5aW5nIGZhY3RvciBjYXVzaW5nIHRoaXMuIFRoaXMgaXMgaW1wb3J0YW50IGlzIGl0IG1lYW5zIHRoYXQgdGhlIGFzc3VtcHRpb24gb2YgaW5kZXBlbmRlbmNlIHRoYXQgcmVncmVzc2lvbiBtb2RlbHMgcmVseSB1cG9uIG1pZ2h0IGJlIHZpb2xhdGVkLgoKTm93IGluIG91ciBjYXNlIGhlcmUsIHRoZXJlIGlzIG5vdCBhIGNsZWFyIHZpb2xhdGlvbiBvZiBzcGF0aWFsIGluZGVwZW5kZW5jZSwgYnV0IGl0IGlzIGNlcnRhaW5seSBoaW50ZWQgYXQuCgo0LiBJbnZlc3RpZ2F0aW5nIGZ1cnRoZXIgLSBEdW1teSBWYXJpYWJsZXMKV2hhdCBpZiBpbnN0ZWFkIG9mIGZpdHRpbmcgb25lIGxpbmUgdG8gb3VyIGNsb3VkIG9mIHBvaW50cywgd2UgY291bGQgZml0IHNldmVyYWwgZGVwZW5kaW5nIG9uIHdoZXRoZXIgdGhlIFdhcmRzIHdlIHdlcmUgYW5hbHlzaW5nIGZlbGwgaW50byBzb21lIG9yIG90aGVyIGdyb3VwLiBXaGF0IGlmIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBhdHRlbmRpbmcgc2Nob29sIGFuZCBhY2hpZXZpbmcgZ29vZCBleGFtIHJlc3VsdHMgdmFyaWVkIGJldHdlZW4gaW5uZXIgYW5kIG91dGVyIExvbmRvbiwgZm9yIGV4YW1wbGUuIENvdWxkIHdlIHRlc3QgZm9yIHRoYXQ/IFdlbGwgeWVzIHdlIGNhbiAtIHF1aXRlIGVhc2lseSBpbiBmYWN0LgoKSWYgd2UgY29sb3VyIHRoZSBwb2ludHMgcmVwcmVzZW50aW5nIFdhcmRzIGZvciBJbm5lciBhbmQgT3V0ZXIgTG9uZG9uIGRpZmZlcmVudGx5LCB3ZSBjYW4gc3RhcnQgdG8gc2VlIHRoYXQgdGhlcmUgbWlnaHQgYmUgc29tZXRoaW5nIGludGVyZXN0aW5nIGdvaW5nIG9uLiBUaGVyZSBzZWVtcyB0byBiZSBhIHN0cm9uZ2VyIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGFic2VuY2UgYW5kIEdDU0Ugc2NvcmVzIGluIE91dGVyIExvbmRvbiB0aGFuIElubmVyIExvbmRvbi4gV2UgY2FuIHRlc3QgZm9yIHRoaXMgaW4gYSBzdGFuZGFyZCBsaW5lYXIgcmVncmVzc2lvbiBtb2RlbC4KCmBgYHtyfQpwIDwtIGdncGxvdChMb25kb25XYXJkc1NGLCBhZXMoeD1VbmF1dGhBYnNlLCB5PUF2Z0dDU0UyMDEpKQpwICsgZ2VvbV9wb2ludChhZXMoY29sb3VyID0gSW5uZXJPdXRlcikpCmBgYAoKRHVtbXkgdmFyaWFibGVzIGFyZSBhbHdheXMgY2F0ZWdvcmljYWwgZGF0YSAoaW5uZXIgb3Igb3V0ZXIgTG9uZG9uLCBvciByZWQgLyBibHVlIGV0Yy4pLiBXaGVuIHdlIGluY29ycG9yYXRlIHRoZW0gaW50byBhIHJlZ3Jlc3Npb24gbW9kZWwsIHRoZXkgc2VydmUgdGhlIHB1cnBvc2Ugb2Ygc3BsaXR0aW5nIG91ciBhbmFseXNpcyBpbnRvIGdyb3Vwcy4gSW4gdGhlIGdyYXBoIGFib3ZlLCBpdCB3b3VsZCBtZWFuLCBlZmZlY3RpdmVseSwgaGF2aW5nIGEgc2VwYXJhdGUgcmVncmVzc2lvbiBsaW5lIGZvciB0aGUgcmVkIHBvaW50cyBhbmQgYSBzZXBhcmF0ZSBsaW5lIGZvciB0aGUgYmx1ZSBwb2ludHMuCgpgYGB7cn0KI2ZpcnN0LCBsZXQncyBtYWtlIHN1cmUgUiBpcyByZWFkaW5nIG91ciBJbm5lck91dGVyIHZhcmlhYmxlIGFzIGEgZmFjdG9yCkxvbmRvbldhcmRzU0YkSW5uZXJPdXRlciA8LSBhcy5mYWN0b3IoTG9uZG9uV2FyZHNTRiRJbm5lck91dGVyKQoKI25vdyBydW4gdGhlIG1vZGVsCm1vZGVsMV9kdW1teSA8LSBsbShBdmdHQ1NFMjAxIH4gVW5hdXRoQWJzZSArIElubmVyT3V0ZXIsIGRhdGEgPSBMb25kb25XYXJkc1NGKQoKc3VtbWFyeShtb2RlbDFfZHVtbXkpCmBgYAoKU28gaG93IGNhbiB3ZSBpbnRlcnByZXQgdGhpcz8KCldlbGwsIHRoZSBkdW1teSB2YXJpYWJsZSBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IGFuZCB0aGUgY29lZmZpY2llbnQgdGVsbHMgdXMgdGhlIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgdHdvIGdyb3VwcyAoSW5uZXIgYW5kIE91dGVyIExvbmRvbikgd2UgYXJlIGNvbXBhcmluZy4gSW4gdGhpcyBjYXNlLCBpdCBpcyB0ZWxsaW5nIHVzIHRoYXQgbGl2aW5nIGluIGEgV2FyZCBpbiBvdXRlciBMb25kb24gd2lsbCBpbXByb3ZlIHlvdXIgYXZlcmFnZSBHQ1NFIHNjb3JlIGJ5IDQuODkgcG9pbnRzLCBvbiBhdmVyYWdlLCBjb21wYXJlZCB0byBpZiB5b3UgbGl2ZWQgaW4gSW5uZXIgTG9uZG9uLiBUaGUgUi1zcXVhcmVkIGhhcyBpbmNyZWFzZWQgc2xpZ2h0bHksIGJ1dCBub3QgYnkgbXVjaC4KCllvdSB3aWxsIG5vdGljZSB0aGF0IGRlc3BpdGUgdGhlcmUgYmVpbmcgdHdvIHZhbHVlcyBpbiBvdXIgZHVtbXkgdmFyaWFibGUgKElubmVyIGFuZCBPdXRlciksIHdlIG9ubHkgZ2V0IG9uZSBjb2VmZmljaWVudC4gVGhpcyBpcyBiZWNhdXNlIHdpdGggZHVtbXkgdmFyaWFibGVzLCBvbmUgdmFsdWUgaXMgYWx3YXlzIGNvbnNpZGVyZWQgdG8gYmUgdGhlIGNvbnRyb2wgKGNvbXBhcmlzb24vcmVmZXJlbmNlKSBncm91cC4gSW4gdGhpcyBjYXNlIHdlIGFyZSBjb21wYXJpbmcgT3V0ZXIgTG9uZG9uIHRvIElubmVyIExvbmRvbi4gSWYgb3VyIGR1bW15IHZhcmlhYmxlIGhhZCBtb3JlIHRoYW4gMiBsZXZlbHMgd2Ugd291bGQgaGF2ZSBtb3JlIGNvZWZmaWNpZW50cywgYnV0IGFsd2F5cyBvbmUgYXMgdGhlIHJlZmVyZW5jZS4KClRoZSBvcmRlciBpbiB3aGljaCB0aGUgZHVtbXkgY29tcGFyaXNvbnMgYXJlIG1hZGUgaXMgZGV0ZXJtaW5lZCBieSB3aGF0IGlzIGtub3duIGFzIGEg4oCYY29udHJhc3QgbWF0cml44oCZLiBUaGlzIGRldGVybWluZXMgdGhlIHRyZWF0bWVudCBncm91cCAoMSkgYW5kIHRoZSBjb250cm9sIChyZWZlcmVuY2UpIGdyb3VwICgwKS4gV2UgY2FuIHZpZXcgdGhlIGNvbnRyYXN0IG1hdHJpeCB1c2luZyB0aGUgY29udHJhc3RzKCkgZnVuY3Rpb246CgpgYGB7cn0KY29udHJhc3RzKExvbmRvbldhcmRzU0YkSW5uZXJPdXRlcikKYGBgCgpJZiB3ZSB3YW50IHRvIGNoYW5nZSB0aGUgcmVmZXJlbmNlIGdyb3VwLCB0aGVyZSBhcmUgdmFyaW91cyB3YXlzIG9mIGRvaW5nIHRoaXMuIFdlIGNhbiB1c2UgdGhlIGNvbnRyYXN0cygpIGZ1bmN0aW9uLCBvciB3ZSBjYW4gdXNlIHRoZSAgcmVsZXZlbCgpIGZ1bmN0aW9uLiBMZXTigJlzIHRyeSBpdDoKCmBgYHtyfQpMb25kb25XYXJkc1NGJElubmVyT3V0ZXIgPC0gcmVsZXZlbChMb25kb25XYXJkc1NGJElubmVyT3V0ZXIsIHJlZj0iT3V0ZXIiKQoKbW9kZWwxX2R1bW15IDwtIGxtKEF2Z0dDU0UyMDEgfiBVbmF1dGhBYnNlICsgSW5uZXJPdXRlciwgZGF0YSA9IExvbmRvbldhcmRzU0YpCnN1bW1hcnkobW9kZWwxX2R1bW15KQpgYGAKCllvdSB3aWxsIG5vdGljZSB0aGF0IHRoZSBvbmx5IHRoaW5nIHRoYXQgaGFzIGNoYW5nZWQgKC00Ljg4OCkgaW4gdGhlIG1vZGVsIGlzIHRoYXQgdGhlIGNvZWZmaWNpZW50IGZvciB0aGUgSW5uZXJPdXRlciB2YXJpYWJsZSBub3cgcmVsYXRlcyB0byBJbm5lciBMb25kb24gYW5kIGlzIG5vdyBuZWdhdGl2ZSAobWVhbmluZyB0aGF0IGxpdmluZyBpbiBJbm5lciBMb25kb24gaXMgbGlrZWx5IHRvIHJlZHVjZSB5b3VyIGF2ZXJhZ2UgR0NTRSBzY29yZSBieSA0Ljg5IHBvaW50cyBjb21wYXJlZCB0byBPdXRlciBMb25kb24pLiBUaGUgcmVzdCBvZiB0aGUgbW9kZWwgaXMgZXhhY3RseSB0aGUgc2FtZS4KCjUuIEludmVzdGlnYXRpbmcgRnVydGhlciAtIEFkZGluZyBNb3JlIEV4cGxhbmF0b3J5IFZhcmlhYmxlcwoKVXAgdW50aWwgdGhpcyBwb2ludCwgdGhlIG1vZGVsIHdlIGhhdmUgZml0dGVkIHVzaW5nIGxtKCloYXMgYmVlbiBleGFjdGx5IHRoZSBzYW1lIGFzIHRoZSBzY2F0dGVyIHBsb3Qgd2UgZHJldyBhdCB0aGUgYmVnaW5uaW5nLiBUaGUgcmVsYXRpb25zaGlwcyBzaG93biBpbiB0aGUgc3RhdGlzdGljYWwgb3V0cHV0cyBvZiB0aGUgbW9kZWwgd2UgY2FuIG9ic2VydmUgaW4gc2NhdHRlciBwbG90LiBPbmUgb2YgdGhlIGdyZWF0IHRoaW5ncyBhYm91dCByZWdyZXNzaW9uIG1vZGVscyBpcyB0aGV5IGFsbG93IHVzIHRvIGdvIGJleW9uZCB0aGUgc2ltcGxlIDItZGltZW5zaW9uYWwgc2NhdHRlciBwbG90IGFuZCBleHRlbmQgb3VyIGFuYXlzaXMgaW50byBtdWx0aXBsZSBkaW1lbnNpb25zLiBCYW0hCgpTbyBsZXTigJlzIGhhdmUgYSBnb+KApgoKSG1tbSwgd2hhdCBvdGhlciB0aGluZ3MgbWlnaHQgYWZmZWN0IHNvbWVvbmXigJlzIHBlcmZvcm1hbmNlIGF0IHNjaG9vbD8gSWYgd2UgbG9vayB0aHJvdWdoIG91ciBzdWl0ZSBvZiBvdGhlciB2YXJpYWJsZXMgKGhlcmUgLSBodHRwczovL3JwdWJzLmNvbS9hZGFtX2Rlbm5ldHQvMjI4NzU2KSB3ZSBjYW4gc2VlIHRoYXQgdGhlcmUgYXJlIHZhcmlvdXMgY2FuZGlkYXRlcy4gU29jaW8tZWNvbm9taWMgZGVwcml2YXRpb24gbWlnaHQgYmUgYSBnb29kIGNhbmRpZGF0ZSAtIGVtcGxveW1lbnQgaXMgYSBwcm94eSBmb3IgdGhpcyAoZW1wbG95ZWQgcGVvcGxlIHRlbmQgdG8gYmUgbW9yZSB3ZWxsLW9mZiB0aGFuIHVuZW1wbG95ZWQgcGVvcGxlKSwgc28gbGV04oCZcyB0cnkgYWRkaW5nIGVtcGxveW1lbnQgaW4uIEluIG91ciBkYXRhc2V0IHdlIGhhdmUgYSB2YXJpYWJsZSBsYWJlbGxlZCDigJhFbXBsb3ltZW504oCZIHdoaWNoIGlzIHRoZSBlbXBsb3ltZW50IHJhdGUgKGFzIGEgJSkgZm9yIDE2LTY0IHllYXIgb2xkcy4KCkZpcnN0IHdlIG5lZWQgdG8gY2hlY2sgdGhhdCBvdXIgdmFyaWFibGUgaXMgbm9ybWFsbHkgZGlzdHJpYnV0ZWQ6CgpgYGB7cn0KcCA8LSBnZ3Bsb3QoTG9uZG9uV2FyZHNTRiwgYWVzKHg9RW1wbG95bWVudCkpCnAgKyBnZW9tX2hpc3RvZ3JhbSgpCmBgYAoKWWVwIGxvb2tzIE9LLiBUaGUgZW1wbG95bWVudCByYXRlIGZvciAxNi02NCB5ZWFyIG9sZHMgbG9va3MgcmVsYXRpdmVseSBub3JtYWxseSBkaXN0cmlidXRlZC4KCk5vdyB3ZSBzaG91bGQgY2hlY2sgdGhhdCBpdOKAmXMgbm90IGhpZ2hseSBjb3JyZWxhdGVkIHdpdGggb3VyIG90aGVyIGluZGVwZW5kZW50IHZhcmlhYmxlc+KApiAoaGlnaGx5IGNvcnJlbGF0ZWQgaW5kZXBlbmRlbnQgdmFyaWFibGVzIHdpbGwgYmlhcyBhbnkgcmVzdWx0cyB3ZSBnZXQpCgpgYGB7cn0KaW5zdGFsbC5wYWNrYWdlcygiY29ycnBsb3QiKQpsaWJyYXJ5KGNvcnJwbG90KQpgYGAKCmBgYHtyfQojdG8gY2hlY2sgZm9yIGNvcnJlbGF0aW9ucywgd2UgY2FuIGNyZWF0ZSBhIGNvcnJlbGF0aW9uIG1hdHJpeCBhbmQgdGhlbiB2aXN1YWxpc2UgaXQgdXNpbmcgdGhlIGNvcnJwbG90IHBhY2thZ2UKI2ZpcnN0LCBjb252ZXJ0IExvbmRvbldhcmRzU0YgdG8gYSBkYXRhIGZyYW1lCkxvbmRvbldhcmRzREYgPC0gc3Rfc2V0X2dlb21ldHJ5KExvbmRvbldhcmRzU0YsTlVMTCkKY29ybWF0IDwtIGNvcihMb25kb25XYXJkc0RGWyw4OjcyXSwgdXNlPSJjb21wbGV0ZS5vYnMiLCBtZXRob2Q9InBlYXJzb24iKQpjb3JycGxvdChjb3JtYXQsIHRsLmNvbD0iYmxhY2siLCB0bC5jZXg9MC40KQoKYGBgCgpgYGB7cn0KIyNvayBxdWl0ZSBiaWcsIGxldCdzIGdvIGEgYml0IHNtYWxsZXIgYW5kIHNlbGVjIGp1c3QgYSBmZXcgdmFyaWFibGVzLi4uCmNvcm1hdCA8LSBjb3IoTG9uZG9uV2FyZHNERlssYygyOCw2MCw2MSw3MSldLCB1c2U9ImNvbXBsZXRlLm9icyIsIG1ldGhvZD0icGVhcnNvbiIpCmNvcnJwbG90KGNvcm1hdCkKYGBgCgpSaWdodCwgc28gaXQgZG9lc27igJl0IGFwcGVhciB0aGF0IHVuYXV0aG9yaXNlZCBhYnNlbmNlIGZyb20gc2Nob29sIGlzIHRvbyBoaWdobHkgY29ycmVsYXRlZCB3aXRoIGVtcGxveW1lbnQgcmF0ZSAobW9kZXJhdGUgbmVnYXRpdmUgY29ycmVsYXRpb24gLSB3aGF0IGlzIGhpZ2ggY29ycmVsYXRpb24gSSBoZWFyIHlvdSBhc2s/IEdvb2QgcXVlc3Rpb24gLSB3ZeKAmWxsIGdvIGZvciAwLjUgYW5kIGFib3ZlIGZvciBub3csIGJ1dCBnb29kIHF1ZXN0aW9uKSwgc28gbGV04oCZcyBwdXQgaXQgaW50byB0aGUgbW9kZWwgYW5kIHNlZSB3aGF0IGl0IGRvZXMgdG8gdGhlIGFuYWx5c2lz4oCmCgpSdW4gdGhlIG1vZGVsIGFnYWluIHdpdGggYSBuZXcgdmFyaWFibGUgYWRkZWQgaW4uCgpgYGB7cn0KbW9kZWwyX2R1bW15IDwtIGxtKEF2Z0dDU0UyMDEgfiBVbmF1dGhBYnNlICsgRW1wbG95bWVudCArIElubmVyT3V0ZXIsIGRhdGEgPSBMb25kb25XYXJkc1NGKQoKc3VtbWFyeShtb2RlbDJfZHVtbXkpCmBgYAoKU28sIHdoYXQgZG8gdGhlIG1vZGVsIG91dHB1dHMgdGVsbCB1cz8KClRoZSBmaXJzdCB0aGluZyB0byBub3RlIGlzIHRoZSBuZXcgdmFyaWFibGUgKGVtcGxveW1lbnQpIGlzIHNpZ25pZmljYW50IChwLXZhbHVlIGlzIDwwLjAwMSBvciAqKiopIGFuZCBwb3NpdGl2ZSwgd2hpY2ggbWVhbnMgdGhhdCBhcyB0aGUgZW1wbG95bWVudCByYXRlIGluIGEgd2FyZCBnb2VzIHVwLCBzbyBkb2VzIHRoZSBhdmVyYWdlIEdDU0UgU2NvcmUKCkZvciBhIDElIGluY3JlYXNlIGluICUgb2YgcGVvcGxlIGVtcGxveWVkIGluIGEgV2FyZCwgd2UgY2FuIGV4cGVjdCBhIDAuNzYgcG9pbnQgaW5jcmVhc2UgaW4gdGhlIGF2ZXJhZ2UgR0NTRSBzY29yZS4KClRoZSBmaXQgb2YgdGhlIG1vZGVsIHJlcHJlc2VudGVkIGJ5IHRoZSBSLXNxdWFyZWQgc2NvcmUgaGFzIGltcHJvdmVkIHRvIGFyb3VuIDQzJSBvZiB0aGUgdmFyaWF0aW9uIGluIEdTQ0Ugc2NvcmVzIG5vdyBleHBsYWluZWQgYnkgdGhlIGluZGVwZW5kZW50IHZhcmlhYmxlcy4KCkluY2x1ZGluZyBlbXBsb3ltZW50IGluIHRoZSBtb2RlbCBoYXMgaW5jcmVhc2VkIHRoZSBwYXJhbWV0ZXIgdmFsdWUgZm9yIHRoZSBpbm5lciAvIG91dGVyIExvbmRvbiBkdW1teSB2YXJpYWJsZS4KCnQtdmFsdWVzIGFyZSBzdGFuZGFyZGlzZWQgY29lZmZpY2llbnQgdmFsdWVzIGFuZCBnaXZlIGEgc2Vuc2Ugb2YgdGhlIGltcG9ydGFuY2Ugb2YgZWFjaCBpbmRlcGVuZGVudCB2YXJpYWJsZSAtIGVzcGVjaWFsbHkgd2hlbiBtZWFzdXJlZCBvbiBkaWZmZXJlbnQgc2NhbGVzICh0aGUgY29lZmZpY2llbnRzIHJlbGF0ZSB0byB0aGUgdW5pdCBvZiBtZWFzdXJlbWVudCkgLSBmcm9tIHRoaXMgd2UgY2FuIHNlZSBjbGVhcmx5IHRoYXQgdW5hdXRob3Jpc2VkIGFic2VuY2UgaXMgdGhlIG1vc3QgaW1wb3J0YW50IHZhcmlhYmxlLCBidXQgZW1wbG95bWVudCBpcyBtb3JlIGltcG9ydGFudCB0aGFuIHRoZSBpbm5lci9vdXRlciBMb25kb24gZHVtbXkgdmFyaWFibGUuCgo2LiBCdWlsZGluZyB0aGUgb3B0aW11bSBtb2RlbAoKQXMgeW91IG1pZ2h0IGhhdmUgZ3Vlc3NlZCwgd2UgY2FuIGtlZXAgZ29pbmcgYW5kIGFkZCBtb3JlIGFuZCBtb3JlIHZhcmlhYmxlcyAoYXMgbG9uZyBhcyB0aGV5IGFyZSBub3QgaGlnaGx5IGNvcnJlbGF0ZWQgd2l0aCBlYWNoIG90aGVyKSB0byB0cnkgYW5kIGV4cGxhaW4gYXMgbXVjaCBvZiBvdXIgaW5kZXBlbmRlbnQgdmFyaWFibGUgYXMgcG9zc2libGUuCgpUYXNrCllvdSBzaG91bGQgdHJ5IGFuZCBidWlsZCB0aGUgb3B0aW11bSBtb2RlbCBvZiBHQ1NFIHBlcmZvcm1hbmNlIGZyb20geW91ciBkYXRhIGluIHlvdXIgTG9uZG9uV2FyZHMgZGF0YXNldC4gRXhwZXJpbWVudCB3aXRoIGFkZGluZyBkaWZmZXJlbnQgdmFyaWFibGVzIC0gd2hlbiBidWlsZGluZyBhIHJlZ3Jlc3Npb24gbW9kZWwgaW4gdGhpcyB3YXksIHlvdSBhcmUgdHJ5aW5nIHRvIGhpdCBhIHN3ZWV0IHNwb3QgYmV0d2VlbiBpbmNyZWFzaW5nIHlvdXIgUi1zcXVhcmVkIHZhbHVlIGFzIG11Y2ggYXMgcG9zc2libGUsIGJ1dCB3aXRoIGFzIGZldyBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYXMgcG9zc2libGUuCgpBIGZldyB0aGluZ3MgdG8gd2F0Y2ggb3V0IGZvcuKApgpZb3Ugc2hvdWxkIG5ldmVyIGp1c3QgdGhyb3cgdmFyaWFibGVzIGF0IGEgbW9kZWwgd2l0aG91dCBhIGdvb2QgdGhlb3JldGljYWwgcmVhc29uIGZvciB3aHkgdGhleSBtaWdodCBoYXZlIGFuIGluZmx1ZW5jZS4gQ2hvb3NlIHlvdXIgdmFyaWFibGVzIGNhcmVmdWxseSEKCkJlIHByZXBhcmVkIHRvIHRha2UgdmFyaWFibGVzIG91dCBvZiB5b3VyIG1vZGVsIGVpdGhlciBpZiBhIG5ldyB2YXJpYWJsZSBjb25mb3VuZHMgKGJlY29tZXMgbW9yZSBpbXBvcnRhbnQgdGhhbikgZWFybGllciB2YXJpYWJsZXMgb3IgdHVybnMgb3V0IG5vdCB0byBiZSBzaWduaWZpY2FudC4KCkZvciBleGFtcGxlLCBsZXTigJlzIHRyeSBhZGRpbmcgdGhlIHJhdGUgb2YgZHJ1Z3MgcmVsYXRlZCBjcmltZSAobG9nZ2VkIGFzIGl0IGlzIGEgcG9zaXRpdmVseSBza2V3ZWQgdmFyaWFibGUsIHdoZXJlIGFzIHRoZSBsb2cgaXMgbm9ybWFsKSBhbmQgdGhlIG51bWJlciBvZiBjYXJzIHBlciBob3VzZWhvbGTigKYKCmBgYHtyfQptb2RlbDNfZHVtbXkgPC0gbG0oQXZnR0NTRTIwMSB+IFVuYXV0aEFic2UgKyBFbXBsb3ltZW50ICsgbG9nKERydWdzUmF0ZTEpICsgQ2Fyc1BlckhIMiArIElubmVyT3V0ZXIsIGRhdGEgPSBMb25kb25XYXJkc1NGKQoKc3VtbWFyeShtb2RlbDNfZHVtbXkpCmBgYAoKSW50ZXJwcmV0YXRpb24KT0ssIHNvIG5vdyB0aGluZ3MgYXJlIGdldHRpbmcgaW50ZXJlc3RpbmcuIE91ciBSLXNxdWFyZWQgdmFsdWUgaGFzIGltcHJvdmVkLCBidXQgd2UgY2FuIHNlZSB0aGF0OgoKT3VyIGRydWcgcmVsYXRlZCBjcmltZSByYXRlIHZhcmlhYmxlIGlzIGluc2lnbmlmaWNhbnQuIFBlcmhhcHMgdW5zdXJwcmlzaW5nIHdoZW4gd2UgdGhpbmsgdmVyeSBjYXJlZnVsbHkgYWJvdXQgaXQgLSBkcnVncyByZWxhdGVkIGNyaW1lIGlzIHJlbGF0aXZlbHkgc21hbGwtc2NhbGUgKGNvbXBhcmVkIHRvIG90aGVyIGNyaW1lcykgYW5kIHRoZXJlZm9yZSB1bmxpa2VseSB0byBhZmZlY3QgdmVyeSBtYW55IHNjaG9vbCBjaGlsZHJlbi4KCkluY2x1ZGluZyBhIGNhcnMgcGVyIGhvdXNlaG9sZCB2YXJpYWJsZSBjb21wbGV0ZWx5IGNvbmZvdW5kcyB0aGUgZWZmZWN0cyBvZiB0aGUgSW5uZXIvT3V0ZXIgTG9uZG9uIGR1bW15IHZhcmlhYmxlLiBUaGlzIGRvZXMgbWFrZSBzZW5zZSBhcyBJbm5lci9PdXRlciBMb25kb24gd2FzIGFsd2F5cyBqdXN0IGEgcHJveHkgZm9yIGFmbHVlbmNlIHdoaWNoIGlzIGNhcHR1cmVkIGZhciBtb3JlIGVmZmVjdGl2ZWx5IHdpdGggdGhlIGNhcnMgcGVyIGhvdXNlaG9sZCB2YXJpYWJsZS4KClRhc2sgLSBjb250aW51ZWQKS2VlcCBleHBlcmllbWVudGluZyB3aXRoIG5ldyBleHBsYW5hdG9yeSB2YXJpYWJsZXMgdW50aWwgeW91IGFyZSBoYXBweSB0aGF0IHlvdSBoYXZlIGJ1aWx0IHlvdXIgb3B0aXVtIG1vZGVsLgoKV2hlbiB5b3UgaGF2ZSBmaW5pc2hlZDoKCndyaXRlIHlvdXIgcmVzaWR1YWwgdmFsdWVzIG91dCB0byB5b3VyIExvbmRvbldhcmRzU0YgZGF0YWZyYW1lCnBsb3QgeW91ciByZXNpZHVhbHMgb24gYSBtYXAgdG8gY2hlY2sgdmlzdWFsbHkgZm9yIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uCnJ1biBhIE1vcmFu4oCZcyBJIHRlc3QgdG8gY29uZmlybSB0aGUgcHJlc2VuY2Ugb3Igb3RoZXJ3aXNlIG9mIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uLgoKVGFzayAzIC0gR2VvZ3JhcGhpY2FsbHkgV2VpZ2h0ZWQgUmVncmVzc2lvbiBNb2RlbHMgKEdXUikKCkhlcmXigJlzIG15IGZpbmFsIG1vZGVsIGZyb20gdGhlIGxhc3Qgc2VjdGlvbjoKCmBgYHtyfQptb2RlbF9maW5hbCA8LSBsbShBdmdHQ1NFMjAxIH4gVW5hdXRoQWJzZSArIEVtcGxveW1lbnQgKyBDYXJzUGVySEgyLCBkYXRhID0gTG9uZG9uV2FyZHNTRikKc3VtbWFyeShtb2RlbF9maW5hbCkKYGBgCgpgYGB7cn0KTG9uZG9uV2FyZHNTRiRtb2RlbF9maW5hbF9yZXMgPC0gbW9kZWxfZmluYWwkcmVzaWR1YWxzCnBsb3QobW9kZWxfZmluYWwpCmBgYAoKYGBge3J9CnF0bShMb25kb25XYXJkc1NGLCBmaWxsID0gIm1vZGVsX2ZpbmFsX3JlcyIpCmBgYAoKYGBge3J9CkxvbmRvbldhcmRzIDwtIGFzKExvbmRvbldhcmRzU0YsIlNwYXRpYWwiKQptb3Jhbi50ZXN0KExvbmRvbldhcmRzQGRhdGEkbW9kZWwxX3Jlc2lkcywgTHdhcmQubHcpCmBgYAoKTm93LCB3ZSBwcm9iYWJseSBjb3VsZCBzdG9wIGF0IHRoaXMgcG9pbnQsIGJ1dCB0aGUgTW9yYW7igJlzIEkgdGVzdCBzdWdnZXN0cyB0aGF0IHRoZXJlIG1pZ2h0IGJlIGEgbGl0dGxlIHNwYXRpYWwgYXV0b2NvcnJlbGF0aW9uIGluIHRoZSByZXNpZHVhbHMsIHRoZXJlZm9yZSBpdCB3aWxsIGJlIHdvcnRoIHNlZWluZyBpZiB3ZSBjYW4gbGVhcm4gZXZlbiBtb3JlIGFib3V0IHRoZSBmYWN0b3JzIGFmZmVjdGluZyBzY2hvb2wgcGVyZm9ybWFuY2UgaW4gTG9uZG9uIHVzaW5nIHNvbWUgZ2VvZ3JhcGhpY2FsbHkgd2VpZ2h0ZWQgbW9kZWxzLgoKVGhpcyBwYXJ0IG9mIHRoZSBwcmFjdGljYWwgd2lsbCBvbmx5IHNraXJ0IHRoZSBlZGdlcyBvZiBHV1IsIGZvciBtdWNoIG1vcmUgZGV0YWlsIHlvdSBzaG91bGQgdmlzaXQgdGhlIEdXUiB3ZWJzaXRlIHdoaWNoIGlzIHByb2R1Y2VkIGFuZCBtYWludGFpbmVkIGJ5IFByb2YgQ2hyaXMgQnJ1bnNkb24gYW5kIERyIE1hcnRpbiBDaGFybHRvbiB3aG8gb3JpZ2luYWxseSBkZXZlbG9wZWQgdGhlIHRlY2huaXF1ZSAtIGh0dHA6Ly9nd3IubnVpbS5pZS8KClRoZXJlIGFyZSB2YXJpb3VzIHBhY2thZ2VzIHdoaWNoIHdpbGwgY2Fycnkgb3V0IEdXUiBpbiBSLCBmb3IgdGhpcyBwcmFjaWNhbCB3ZSB3ZSB1c2Ugc3Bnd3IgKG1haW5seSBiZWNhdXNlIGl0IHdhcyB0aGUgZmlyc3Qgb25lIEkgY2FtZSBhY3Jvc3MpLCBhbHRob3VnaCB5b3UgY291bGQgYWxzbyB1c2UgR1dtb2RlbCBvciBnd3JyLiBBdCB0aGUgZW5kIG9mIHRoaXMgcHJhY3RpY2FsLCB5b3UgY2FuIHRlc3Qgb3V0IHRoZXNlIGlkZWFzIGluIEFyY0dJUyB1c2luZyB0aGUgR1dSIHRvb2xzZXQgaW4gdGhlIFNwYXRpYWwgU3RhdGlzdGljcyBUb29sYm94IC0gCgpJIHNob3VsZCBhbHNvIGFja25vd2xlZGdlIHRoZSBndWlkZSBvbiBHV1IgKGFjY2Vzc2libGUgaGVyZTogaHR0cDovL3d3dy5icmlzLmFjLnVrL2NtcG8vZXZlbnRzLzIwMDkvc2VncmVnYXRpb24vZ3dyLnBkZikgcHJvZHVjZWQgYnkgdGhlIFVuaXZlcnNpdHkgb2YgQnJpc3RvbCwgd2hpY2ggd2FzIGEgZ3JlYXQgaGVscCB3aGVuIHByb2R1Y2luZyB0aGlzIGV4ZXJjaXNlLgoKYGBge3J9Cmluc3RhbGwucGFja2FnZXMoInNwZ3dyIikKbGlicmFyeShzcGd3cikKYGBgCgpgYGB7cn0KI2NhbGN1bGF0ZSBrZXJuZWwgYmFuZHdpZHRoCkdXUmJhbmR3aWR0aCA8LSBnd3Iuc2VsKEF2Z0dDU0UyMDEgfiBVbmF1dGhBYnNlICsgRW1wbG95bWVudCArIENhcnNQZXJISDIsIGRhdGEgPSBMb25kb25XYXJkcywgY29vcmRzPWNiaW5kKHgseSksYWRhcHQ9VCkgCmBgYAoKYGBge3J9CiNydW4gdGhlIGd3ciBtb2RlbApnd3IubW9kZWwgPSBnd3IoQXZnR0NTRTIwMSB+IFVuYXV0aEFic2UgKyBFbXBsb3ltZW50ICsgQ2Fyc1BlckhIMiwgZGF0YT1Mb25kb25XYXJkcywgY29vcmRzPWNiaW5kKHgseSksIGFkYXB0PUdXUmJhbmR3aWR0aCwgaGF0bWF0cml4PVRSVUUsIHNlLmZpdD1UUlVFKSAKYGBgCgpgYGB7cn0KI3ByaW50IHRoZSByZXN1bHRzIG9mIHRoZSBtb2RlbApnd3IubW9kZWwKYGBgCgpUaGUgb3V0cHV0IGZyb20gdGhlIEdXUiBtb2RlbCByZXZlYWxzIGhvdyB0aGUgY29lZmZpY2llbnRzIHZhcnkgYWNyb3NzIHRoZSA2MjUgV2FyZHMgaW4gb3VyIExvbmRvbiBTdHVkeSByZWdpb24uIFlvdSB3aWxsIHNlZSBob3cgdGhlIGdsb2JhbCBjb2VmZmljaWVudHMgYXJlIGV4YWN0bHkgdGhlIHNhbWUgYXMgdGhlIGNvZWZmaWNpZW50cyBpbiB0aGUgZWFybGllciBsbSBtb2RlbC4gSW4gdGhpcyBwYXJ0aWN1bGFyIG1vZGVsICh5b3VycyB3aWxsIGxvb2sgYSBsaXR0bGUgZGlmZmVyZW50IGlmIHlvdSBoYXZlIHVzZWQgZGlmZmVyZW50IGV4cGxhbmF0b3J5IHZhcmlhYmxlcyksIGlmIHdlIHRha2UgdW5hdXRob3Jpc2VkIGFic2VuY2UgZnJvbSBzY2hvb2wsIHdlIGNhbiBzZWUgdGhhdCB0aGUgY29lZmZpY2llbnRzIHJhbmdlIGZyb20gYSBtaW5pbXVtIHZhbHVlIG9mIC01NC40MSAoMSB1bml0IGNoYW5nZSBpbiB1bmF1dGhvcmlzZWQgYWJzZW5jZSByZXN1bHRpbmcgaW4gYSBkcm9wIGluIGF2ZXJhZ2UgR0NTRSBzY29yZSBvZiAtNTQuNDEpIHRvICsyNy4xNCAoMSB1bml0IGNoYW5nZSBpbiB1bmF1dGhvcmlzZWQgYWJzZW5jZSByZXN1bHRpbmcgaW4gYW4gaW5jcmVhc2UgaW4gYXZlcmFnZSBHQ1NFIHNjb3JlIG9mICsyNy4xNCkuIEZvciBoYWxmIG9mIHRoZSB3YXJkcyBpbiB0aGUgZGF0YXNldCwgYXMgdW5hdXRob3Jpc2VkIGFic2VuY2UgcmlzZXMgYnkgMSBwb2ludCwgR0NTRSBzY29yZXMgd2lsbCBkZWNyZWFzZSBiZXR3ZWVuIC0yNi42MiBhbmQgLTkuMjYgcG9pbnRzICh0aGUgaW50ZXItcXVhcnRpbGUgcmFuZ2UgYmV0d2VlbiB0aGUgMXN0IFF1IGFuZCB0aGUgM3JkIFF1KS4KCllvdSB3aWxsIG5vdGljZSB0aGF0IHRoZSBSLVNxdWFyZWQgdmFsdWUgaGFzIGltcHJvdmVkIC0gdGhpcyBpcyBub3QgdW5jb21tb24gZm9yIEdXUiBtb2RlbHMsIGJ1dCBpdCBkb2VzbuKAmXQgbmVjZXNzYXJpbHkgbWVhbiB0aGV5IGFyZSBkZWZpbml0ZWx5IGJldHRlciB0aGFuIGdsb2JhbCBtb2RlbHMuIFRoZSBzbWFsbCBudW1iZXIgb2YgY2FzZXMgdW5kZXIgdGhlIGtlcm5lbCBtZWFucyB0aGF0IEdXIG1vZGVscyBoYXZlIGJlZW4gY3JpdGljaXNlZC4KCkNvZWZmaWNpZW50IHJhbmdlcyBjYW4gYWxzbyBiZSBzZWVuIGZvciB0aGUgb3RoZXIgdmFyaWFibGVzIGFuZCB0aGV5IHN1Z2dlc3Qgc29tZSBpbnRlcmVzdGluZyBzcGF0aWFsIHBhdHRlcm5pbmcuIFRvIGV4cGxvcmUgdGhpcyB3ZSBjYW4gcGxvdCB0aGUgR1dSIGNvZWZmaWNpZW50cyBmb3IgZGlmZmVyZW50IHZhcmlhYmxlcy4gRmlyc3RseSB3ZSBjYW4gYXR0YWNoIHRoZSBjb2VmZmljaWVudHMgdG8gb3VyIG9yaWdpbmFsIGRhdGFmcmFtZSAtIHRoaXMgY2FuIGJlIGFjaGlldmVkIHNpbXBseSBhcyB0aGUgY29lZmZpY2llbnRzIGZvciBlYWNoIHdhcmQgYXBwZWFyIGluIHRoZSBzYW1lIG9yZGVyIGluIG91ciBzcGF0aWFsIHBvaW50cyBkYXRhZnJhbWUgYXMgdGhleSBkbyBpbiB0aGUgb3JpZ2luYWwgZGF0YWZyYW1lLgoKYGBge3J9CnJlc3VsdHM8LWFzLmRhdGEuZnJhbWUoZ3dyLm1vZGVsJFNERikKaGVhZChyZXN1bHRzKQpgYGAKCmBgYHtyfQojYXR0YWNoIGNvZWZmaWNpZW50cyB0byBvcmlnaW5hbCBkYXRhZnJhbWUKTG9uZG9uV2FyZHNAZGF0YSRjb2VmVW5hdXRoQWJzZTwtcmVzdWx0cyRVbmF1dGhBYnNlCkxvbmRvbldhcmRzQGRhdGEkY29lZkVtcGxveW1lbnQ8LXJlc3VsdHMkRW1wbG95bWVudApMb25kb25XYXJkc0BkYXRhJGNvZWZDYXJzUGVySEgyPC1yZXN1bHRzJENhcnNQZXJISDIKYGBgCgpgYGB7cn0KdG1fc2hhcGUoTG9uZG9uV2FyZHMpICsKICB0bV9wb2x5Z29ucyhjb2wgPSAiY29lZlVuYXV0aEFic2UiLCBwYWxldHRlID0gIlJkQnUiKQpgYGAKCmBgYHtyfQp0bV9zaGFwZShMb25kb25XYXJkcykgKwogIHRtX3BvbHlnb25zKGNvbCA9ICJjb2VmRW1wbG95bWVudCIsIHBhbGV0dGUgPSAiUmRCdSIpCmBgYAoKYGBge3J9CnRtX3NoYXBlKExvbmRvbldhcmRzKSArCiAgdG1fcG9seWdvbnMoY29sID0gImNvZWZDYXJzUGVySEgyIiwgcGFsZXR0ZSA9ICJSZEJ1IikKYGBgCgpUYWtpbmcgdGhlIGZpcnN0IHBsb3QsIHdoaWNoIGlzIGZvciB0aGUgdW5hdXRob3Jpc2VkIGFic2VuY2UgY29lZmZpY2llbnRzLCB3ZSBjYW4gc2VlIHRoYXQgZm9yIHRoZSBtYWpvcml0eSBvZiBib3JvdWdocyBpbiBMb25kb24sIHRoZXJlIGlzIHRoZSBuZWdhdGl2ZSByZWxhdGlvbnNoaXAgd2Ugd291bGQgZXhwZWN0IC0gaS5lLiBhcyB1bmF1dGhvcmlzZWQgYWJzZW5jZSBnb2VzIHVwLCBleGFtIHNjb3JlcyBnbyBkb3duLiBGb3IgdGhyZWUgYm9yb3VnaHMgKFdlc3RtaW5zdGVyLCBLZW5zaW5ndG9uICYgQ2hlbHNlYSBhbmQgSGFtbWVyc21pdGggYW5kIEZ1bGhhbSAtIHRoZSByaWNoZXN0IGluIExvbmRvbiksIGhvd2V2ZXIsIHRoZSByZWxhdGlvbnNoaXAgaXMgcG9zaXRpdmUgLSBhcyB1bmF1dGhvcmlzZWQgc2Nob29sIGFic2VuY2UgaW5jcmVhc2VzLCBzbyBkb2VzIGF2ZXJhZ2UgR0NTRSBzY29yZS4gVGhpcyBpcyBhIHZlcnkgaW50ZXJlc3RpbmcgcGF0dGVybiBhbmQgY291bnRlcmludHVpdGl2ZSBwYXR0ZXJuLCBidXQgbWF5IHBhcnRseSBiZSBleHBsYWluZWQgdGhlIG11bHRpcGxlIGhvbWVzIG93bmVkIGJ5IG1hbnkgbGl2aW5nIGluIHRoZXNlIGJvcm91Z2hzIChzdHVkZW50cyBsaXZpbmcgaW4gZGlmZmVyZW50IHBhcnRzIG9mIHRoZSBjb3VudHJ5IGFuZCBpbmRlZWQgdGhlIHdvcmxkIGZvciBzaWduaWZpY2FudCBwZXJpb2RzIG9mIHRoZSB5ZWFyKSBhbmQgdGhlIG92ZXIgcmVwcmVzZW50YXRpb24gb2YgcHJpdmF0ZSBzY2hvb2xpbmcgb2YgdGhvc2UgbGl2aW5nIGluIHRoZXNlIGFyZWFzLiBJZiB0aGlzIGlzIG5vdCB0aGUgY2FzZSBhbmQgdW5hdXRob3Jpc2VkIGFic2VuY2UgZnJvbSBzY2hvb2wgaXMgcmVmbGVjdGluZyB0aGUgdW5hdXRob3Jpc2VkIGFic2VuY2Ugb2YgcG9vcmVyIHN0dWRlbnRzIGF0dGVuZGluZyBsb2NhbCwgaW5uZXIgY2l0eSBzY2hvb2xzLCB0aGVuIGhpZ2ggR0NTRSBncmFkZXMgbWF5IGFsc28gcmVmbGVjdCB0aGUgYWNoaWV2ZW1lbnRzIG9mIHRob3NlIHdobyBhcmUgc2VudCBhd2F5IHRvIGV4cGVuc2l2ZSBmZWUtcGF5aW5nIHNjaG9vbHMgZWxzZXdoZXJlIGluIHRoZSBjb3VudHJ5IGFuZCB3aG8gcmV0dXJuIHRvIHRoZWlyIHBhcmVudGFsIGhvbWVzIGxhdGVyIGluIHRoZSB5ZWFyLiBFaXRoZXIgd2F5LCB0aGVzZSBmYWN0b3JzIGNvdWxkIGV4cGxhaW4gdGhlc2UgcmVzdWx0cy4KCk9mIGNvdXJzZSwgdGhlc2UgcmVzdWx0cyBtYXkgbm90IGJlIHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnQgYWNyb3NzIHRoZSB3aG9sZSBvZiBMb25kb24uIFJvdWdobHkgc3BlYWtpbmcsIGlmIGEgY29lZmZpY2llbnQgZXN0aW1hdGUgaXMgbW9yZSB0aGFuIDIgc3RhbmRhcmQgZXJyb3JzIGF3YXkgZnJvbSB6ZXJvLCB0aGVuIGl0IGlzIOKAnHN0YXRpc3RpY2FsbHkgc2lnbmlmaWNhbnTigJ0uCgpUbyBjYWxjdWxhdGUgc3RhbmRhcmQgZXJyb3JzLCBmb3IgZWFjaCB2YXJpYWJsZSB5b3UgY2FuIHVzZSBhIGZvcm11bGEgc2ltaWxhciB0byB0aGlzOgoKYGBge3J9CnNpZ1Rlc3QgPSBhYnMoZ3dyLm1vZGVsJFNERiRVbmF1dGhBYnNlKSAtMiAqIGd3ci5tb2RlbCRTREYkVW5hdXRoQWJzZV9zZSAKCkxvbmRvbldhcmRzJEdXUlVuYXV0aFNpZzwtc2lnVGVzdAoKI3RtYXB0b29sczo6cGFsZXR0ZV9leHBsb3JlcigpCmBgYAoKSWYgdGhpcyBpcyBncmVhdGVyIHRoYW4gemVybyAoaS5lLiB0aGUgZXN0aW1hdGUgaXMgbW9yZSB0aGFuIHR3byBzdGFuZGFyZCBlcnJvcnMgYXdheSBmcm9tIHplcm8pLCBpdCBpcyB2ZXJ5IHVubGlrZWx5IHRoYXQgdGhlIHRydWUgdmFsdWUgaXMgemVybywgaS5lLiBpdCBpcyBzdGF0aXN0aWNhbGx5IHNpZ25pZmljYW50IChhdCBuZWFybHkgdGhlIDk1JSBjb25maWRlbmNlIGxldmVsKQoKWW91IHNob3VsZCBub3cgY2FsY3VsYXRlIHRoZXNlIGZvciBlYWNoIHZhcmlhYmxlIGluIHlvdXIgR1dSIG1vZGVsIGFuZCBTZWUgaWYgeW91IGNhbiBwbG90IHRoZW0gb24gYSBtYXAsIGZvciBleGFtcGxlOgoKYGBge3J9CnRtX3NoYXBlKExvbmRvbldhcmRzKSArCiAgdG1fcG9seWdvbnMoY29sID0gIkdXUlVuYXV0aFNpZyIsIHBhbGV0dGUgPSAiUmRZbEJ1IikKYGBgCgpGcm9tIHRoZSByZXN1bHRzIG9mIHlvdXIgR1dSIGV4ZXJjaXNlLCB3aGF0IGFyZSB5b3UgYWJsZSB0byBjb25jbHVkZSBhYm91dCB0aGUgZ2VvZ3JhcGhpY2FsIHZhcmlhdGlvbiBpbiB5b3VyIGV4cGxhbmF0b3J5IHZhcmlhYmxlcyB3aGVuIHByZWRpY3RpbmcgeW91ciBkZXBlbmRlbnQgdmFyaWFibGU/CgoKCgo=